
import Vapor
import Fluent

struct EmployeeController: RouteCollection {
  func boot(routes: RoutesBuilder) throws {
    let employeeRoutes = routes.grouped("api", "employee")
    employeeRoutes.get(use: getAllHandler)
    employeeRoutes.post(use: createHandler)
    //Just for Migrate

    employeeRoutes.post("createCountryAndLanguage", use: createWithLanguageAndCountry)

    employeeRoutes.get(":employeeID", use: getHandler)
    employeeRoutes.put(":employeeID", use: updateHandler)
    employeeRoutes.delete(":employeeID", use: deleteHandler)
    employeeRoutes.post(":employeeID", "country", ":countryID", use: addCountriesHandler)
    employeeRoutes.post(":employeeID", "language", ":languageID", use: addLanguagesHandler)

    employeeRoutes.get(":employeeID", "country", use: getCountriesHandler)
    employeeRoutes.get(":employeeID", "language", use: getLanguagesHandler)

    employeeRoutes.delete(":employeeID", "country", ":countryID", use: removeCountriesHandler)
    employeeRoutes.delete(":employeeID", "language", ":languageID", use: removeLanguagesHandler)
  }
  
  func getAllHandler(_ req: Request) throws -> EventLoopFuture<[Employee]> {
    Employee.query(on: req.db).all()
  }
  
  func createHandler(_ req: Request) throws -> EventLoopFuture<Employee> {
    let data = try req.content.decode(Employee.self)
    return data.save(on: req.db).map { data }
  }

  func getHandler(_ req: Request) throws -> EventLoopFuture<Employee> {
    Employee.find(req.parameters.get("employeeID"), on: req.db)
    .unwrap(or: Abort(.notFound))
  }
    //Just for Migrate

    func createWithLanguageAndCountry(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
        let data = try req.content.decode(EmployeeData.self)
        let employee = Employee(id: data.id, abbreviation: data.abbreviation, firstName: data.firstName, lastName: data.lastName, jobTitle: data.jobTitle, jobDescription: data.jobDescription, email: data.email, telephoneNumber: data.telephoneNumber, mobileNumber: data.mobileNumber, skypeNumber: data.skypeNumber, isMale: data.isMale)

        let queryLanguage = Language.query(on: req.db).all()
        let queryCountries = Country.query(on: req.db).all()
        


        return employee.save(on: req.db).flatMap {
            return queryLanguage.and(queryCountries).flatMap { (languages, countries)  in
                let needToLanguages = languages.filter { (language)  in
                   data.speaksLanguages.contains(language.iso)
                }
                
                let needToCountries = countries.filter { (country) -> Bool in
                    data.responsibleForCountries.contains(country.iso)
                }
                
                let languageAttach = employee.$speaksLanguages.attach(needToLanguages, on: req.db)
                
                let countryAttach = employee.$responsibleForCountries.attach(needToCountries, on: req.db)
                
                return languageAttach.and(countryAttach).map {_ in
                    return HTTPResponseStatus.created
                }
                
            }
        }


    }

  func updateHandler(_ req: Request) throws -> EventLoopFuture<Employee> {
    
    let updateData = try req.content.decode(Employee.self)
    return Employee.find(req.parameters.get("employeeID"), on: req.db)
      .unwrap(or: Abort(.notFound)).flatMap { employee in
        employee.abbreviation = updateData.abbreviation
        employee.firstName = updateData.firstName
        employee.lastName = updateData.lastName
        employee.jobTitle = updateData.jobTitle
        employee.jobDescription = updateData.jobDescription
        employee.email = updateData.email
        employee.telephoneNumber = updateData.telephoneNumber
        employee.mobileNumber = updateData.mobileNumber
        employee.skypeNumber = updateData.skypeNumber
        employee.isMale = updateData.isMale

        return employee.save(on: req.db).map {
            employee
        }
    }
  }

  func deleteHandler(_ req: Request)
    throws -> EventLoopFuture<HTTPStatus> {
    Employee.find(req.parameters.get("employeeID"), on: req.db)
      .unwrap(or: Abort(.notFound))
      .flatMap { employee in
        employee.delete(on: req.db)
          .transform(to: .noContent)
    }
  }
  
  func addCountriesHandler(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
    let employeeQuery = Employee.find(req.parameters.get("employeeID"), on: req.db).unwrap(or: Abort(.notFound))
    let countryQuery = Country.find(req.parameters.get("countryID"), on: req.db).unwrap(or: Abort(.notFound))
    return employeeQuery.and(countryQuery).flatMap { employee, country in
        employee.$responsibleForCountries.attach(country, on: req.db).transform(to: .created)
    }
  }
    
    func addLanguagesHandler(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
        let employeeQuery = Employee.find(req.parameters.get("employeeID"), on: req.db).unwrap(or: Abort(.notFound))
      let languageQuery = Language.find(req.parameters.get("languageID"), on: req.db).unwrap(or: Abort(.notFound))
    
      return employeeQuery.and(languageQuery).flatMap { employee, language in
        employee.$speaksLanguages.attach(language, on: req.db).transform(to: .created)
      }
    }
  
  func getCountriesHandler(_ req: Request) throws -> EventLoopFuture<[Country]> {
    Employee.find(req.parameters.get("employeeID"), on: req.db)
    .unwrap(or: Abort(.notFound))
    .flatMap { employee in
        employee.$responsibleForCountries.query(on: req.db).all()
    }
  }
    func getLanguagesHandler(_ req: Request) throws -> EventLoopFuture<[Language]> {
        Employee.find(req.parameters.get("employeeID"), on: req.db)
      .unwrap(or: Abort(.notFound))
      .flatMap { employee in
        employee.$speaksLanguages.query(on: req.db).all()
      }
    }
  
  func removeCountriesHandler(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
    let employeeQuery = Employee.find(req.parameters.get("employeeID"), on: req.db).unwrap(or: Abort(.notFound))
    let countryQuery = Country.find(req.parameters.get("countryID"), on: req.db).unwrap(or: Abort(.notFound))
    return employeeQuery.and(countryQuery).flatMap { employee, country in
        employee.$responsibleForCountries.detach(country, on: req.db).transform(to: .noContent)
    }
  }
    
    func removeLanguagesHandler(_ req: Request) throws -> EventLoopFuture<HTTPStatus> {
        let employeeQuery = Employee.find(req.parameters.get("employeeID"), on: req.db).unwrap(or: Abort(.notFound))
      let languageQuery = Language.find(req.parameters.get("languageID"), on: req.db).unwrap(or: Abort(.notFound))
      return employeeQuery.and(languageQuery).flatMap { employee, language in
        employee.$speaksLanguages.detach(language, on: req.db).transform(to: .noContent)
  //        department.$employees.detach(employee, on: req.db).transform(to: .noContent)
      }
    }
}

struct EmployeeData: Content {
    var id: UUID
     
     var abbreviation: String
     
     var firstName: String
     
     var lastName: String
     
     var jobTitle: String
     
     var jobDescription: String
     
     var email: String
     
     var telephoneNumber: String
     
     var mobileNumber: String
     
     var skypeNumber: String
     
     var isMale: Bool
    
    var responsibleForCountries:[String]
    var speaksLanguages: [String]

}

